package bblvolume

import (
	"fmt"
	"net"
	"net/http"
	"time"
)

const (
	MAJOR_VERSION       = "0"
	MINOR_VERSION       = "1"
	SERVER_NAME         = "vols"
	STORAGE_NAME_PREFIX = "vols-"
	Author              = "G.Q.F"
	Mail                = "gao.qingfeng@gmail.com"
	License             = "GPL"
)

func version() string {
	return MAJOR_VERSION + "." + MINOR_VERSION
}

func server_name() string {
	return SERVER_NAME + "/" + version()
}

func copyright() string {
	return "Server: " + server_name() + "\nAuthor: " + Author + "\nMail: " + Mail + "\nLicense: " + License
}

type VolumeServer struct {
	UUID        string   `json:"uuid"`
	Name        string   `json:"name"`
	Listen      string   `json:"listen"`
	TranAddr    string   `json:"tranaddr"`
	Export      string   `json:"export"`
	Workdir     string   `json:"-"`
	MountDev    string   `json:"-"`
	Type        string   `json:"type"`
	ClusterAddr []string `json:"-"`
	Passphrase  string   `json:"-"`
	listener    net.Listener
	worker      *WorkerServer
	fs          StorageSystem
}

func (v *VolumeServer) Init() error {
	ll, e := net.Listen("tcp", v.Listen)
	if e != nil {
		log.Error(e)
		return e
	}
	v.listener = ll
	fs, e := NewPosixFileSystem(v.UUID, v.ClusterAddr, v.Passphrase, v.TranAddr, v.Export)
	if e != nil {
		log.Error(e)
		return e
	}
	v.fs = fs
	ws, err := NewWorkerServer(fs)
	if err != nil {
		log.Error(e)
		return err
	}
	v.worker = ws
	return nil
}
func (v *VolumeServer) Serve() {
	server := http.Server{
		ReadTimeout:    90 * time.Minute,
		WriteTimeout:   90 * time.Minute,
		MaxHeaderBytes: 1 << 20,
		Handler:        NewVolumeMux(v.fs, v),
	}
	server.SetKeepAlivesEnabled(true)
	go server.Serve(v.listener)
	log.Info("volume server " + v.UUID + "/" + v.Name + " listen at " + v.Listen)
	_call_join(v)
	v.worker.Serve()
}

func (v *VolumeServer) Stop() {
	log.Info("volume server " + v.UUID + "/" + v.Name + " stopped")
	if v.listener != nil {
		v.listener.Close()
		v.listener = nil
		_call_leave(v)
	}
	if v.worker != nil {
		v.worker.Stop()
		v.worker = nil
	}
}

const (
	join_fmt = `{"uuid":"%v","name":"%v","tran_addr":"%v","export":"%v"}`
)

func _call_join(v *VolumeServer) {
	for {
		body := fmt.Sprintf(join_fmt, v.UUID, v.Name, v.TranAddr, v.Export)
		err := Join(v.ClusterAddr[0], v.UUID, body)
		if err != nil {
			log.Error(err)
			Sleep(1000)
		} else {
			break
		}
	}
}

func _call_leave(v *VolumeServer) {
	for {
		err := Leave(v.ClusterAddr[0], v.UUID)
		if err != nil {
			log.Error(err)
		} else {
			break
		}
	}
}
